home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 46
/
Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso
/
-serious-
/
programming
/
other
/
gtdrag
/
examples
/
boopsi.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-06
|
16KB
|
542 lines
;/* boopsi.c - Test for the gtdrag.library, 7.6.1999
;**
;** Copyright ©1999 pinc Software.
;** All rights reserved.
;**
sc boopsi.c lib:debug.lib nodbg nostkchk link ign=73 to=ram:boopsi
run ram:boopsi
quit
*/
/* This example shows how to create a custom (BOOPSI) gadget
** with support for drag&drop.
**
** It's a very simple example but you may use this code to produce
** one at your own.
**
** Although I tried hardly to not produce any errors, I cannot give
** any guaranties. Neither I nor pinc Software is liable for any
** problems you might have with it.
** The usage of this example is on your own risk.
*/
#define INTUI_V36_NAMES_ONLY
#include <exec/memory.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/icclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/imageclass.h>
#include <intuition/sghooks.h>
#include <graphics/gfx.h>
#include <libraries/gadtools.h>
#include <libraries/gtdrag.h>
#include <clib/console_protos.h>
#include <pragmas/console_pragmas.h>
#include <clib/gtdrag_protos.h>
#include <pragmas/gtdrag_pragmas.h>
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <strings.h>
#include <math.h>
#define reg(x) register __ ## x
#define PUBLIC __saveds __asm
#define bug kprintf
#define foreach(l,v) for(v = (APTR)((struct List *)l)->lh_Head;((struct Node *)v)->ln_Succ;v = (APTR)((struct Node *)v)->ln_Succ)
#define IsBoopsiGadget(gad) ((gad->GadgetType & GTYP_GTYPEMASK) == GTYP_CUSTOMGADGET)
void kprintf(STRPTR,...);
void processMsg(void);
struct Library *GTDragBase;
struct Window *win;
Class *simplegclass;
long fontheight;
struct List list;
/********************************** Simple-Gadget **********************************/
struct SimpleGData
{
struct MinList *sd_List; /* the list to display */
ULONG sd_Items; /* number of items to be displayed */
ULONG sd_Selected; /* currently selected item */
ULONG sd_Range; /* width/height of an item */
ULONG sd_CurrentDrag; /* currently dragged item */
BOOL sd_Direction; /* horizontal or vertical direction? */
struct Hook *sd_Hook; /* hook to render the items */
};
#define SDD_VERTICAL 0
#define SDD_HORIZONTAL 1
#define SDA_List (TAG_USER | 0x10000)
#define SDA_Items (TAG_USER | 0x10001)
#define SDA_Direction (TAG_USER | 0x10002) /* one of the SDD_### */
/** draws the simple gadget */
void DrawSimpleGadget(struct RastPort *rp,struct Gadget *gad,struct GadgetInfo *gi,struct SimpleGData *sd,BOOL all)
{
struct Node *ln;
struct LVDrawMsg lvdm;
UWORD *pens = gi->gi_DrInfo->dri_Pens;
long i,width,height;
/*** draw gadget frame ***/
if (all)
{
struct Image *im;
if (im = NewObject(NULL,"frameiclass",IA_Width, gad->Width,
IA_Height, gad->Height,
IA_FrameType, FRAME_BUTTON,
TAG_END))
{
DrawImage(rp,im,gad->LeftEdge,gad->TopEdge);
DisposeObject(im);
}
}
width = 0; height = 0;
/*** render gadet contents, without any optimisations ***/
if (sd->sd_Direction == SDD_HORIZONTAL)
width = sd->sd_Range;
else
height = sd->sd_Range;
/* initialize listview callback render hook message */
lvdm.lvdm_MethodID = LV_DRAW;
lvdm.lvdm_RastPort = rp;
lvdm.lvdm_DrawInfo = gi->gi_DrInfo;
lvdm.lvdm_Bounds.MinX = gad->LeftEdge+4;
lvdm.lvdm_Bounds.MinY = gad->TopEdge+4;
lvdm.lvdm_Bounds.MaxX = lvdm.lvdm_Bounds.MinX+(width ? width-1 : gad->Width-9);
lvdm.lvdm_Bounds.MaxY = lvdm.lvdm_Bounds.MinY+(height ? height-1 : gad->Height-9);
lvdm.lvdm_State = LVR_NORMAL;
if (!sd->sd_List)
return;
/* display the whole list */
SetABPenDrMd(rp,pens[TEXTPEN],pens[FILLPEN],JAM2);
for(i = 0,ln = (APTR)sd->sd_List->mlh_Head;ln->ln_Succ;ln = ln->ln_Succ,i++)
{
if (i >= sd->sd_Items)
break;
if (sd->sd_Selected == i)
lvdm.lvdm_State = LVR_SELECTED;
CallHookPkt(sd->sd_Hook,ln,&lvdm);
if (sd->sd_Direction == SDD_HORIZONTAL)
{
lvdm.lvdm_Bounds.MinX += width;
lvdm.lvdm_Bounds.MaxX += width;
}
else
{
lvdm.lvdm_Bounds.MinY += height;
lvdm.lvdm_Bounds.MaxY += height;
}
lvdm.lvdm_State = LVR_NORMAL;
}
}
/** dispatch the OM_NEW method */
BOOL DispatchSimpleNew(struct opSet *ops,Object *o,struct SimpleGData *sd)
{
SetAttrs(o,GA_Immediate,TRUE,TAG_END);
sd->sd_List = (APTR)GetTagData(SDA_List,NULL,ops->ops_AttrList);
sd->sd_Items = GetTagData(SDA_Items,1,ops->ops_AttrList);
sd->sd_Direction = GetTagData(SDA_Direction,SDD_VERTICAL,ops->ops_AttrList);
sd->sd_Hook = GTD_GetHook(GTDH_IMAGE);
sd->sd_Selected = sd->sd_CurrentDrag = ~0L;
if (!sd->sd_Items)
return(FALSE);
sd->sd_Range = (sd->sd_Direction == SDD_HORIZONTAL ? ((struct Gadget *)o)->Width-8 : ((struct Gadget *)o)->Height-8)/sd->sd_Items;
return(TRUE);
}
/** dispatch all methods.
*
* To mark the drag&drop related methods, these are separated
* from the other and, furthermore, they are commented.
*/
ULONG PUBLIC DispatchSimpleGadget(reg (a0) Class *cl,reg (a2) Object *o,reg (a1) Msg msg)
{
struct SimpleGData *sd;
ULONG retval = 0;
sd = INST_DATA(cl,o);
switch(msg->MethodID)
{
case OM_NEW:
if (retval = DoSuperMethodA(cl,o,msg))
{
sd = INST_DATA(cl,retval);
if (!DispatchSimpleNew((struct opSet *)msg,(Object *)retval,sd))
{
DoSuperMethod(cl,(Object *)retval,OM_DISPOSE);
retval = NULL;
}
}
break;
case OM_DISPOSE:
retval = DoSuperMethodA(cl,o,msg);
break;
case OM_SET:
case OM_UPDATE:
case OM_NOTIFY:
DoSuperMethodA(cl,o,msg);
{
struct TagItem *tstate,*ti;
tstate = ((struct opSet *)msg)->ops_AttrList;
while(ti = NextTagItem(&tstate))
{
switch(ti->ti_Tag)
{
case SDA_List:
{
struct RastPort *rp = ObtainGIRPort(((struct opUpdate *)msg)->opu_GInfo);
sd->sd_List = (APTR)ti->ti_Data;
DrawSimpleGadget(rp,(struct Gadget *)o,NULL,sd,FALSE);
ReleaseGIRPort(rp);
break;
}
}
}
}
break;
case OM_GET:
if (((struct opGet *)msg)->opg_AttrID == SDA_List)
{
*((struct opGet *)msg)->opg_Storage = (ULONG)sd->sd_List;
retval = TRUE;
}
else
retval = DoSuperMethodA(cl,o,msg);
break;
case GM_RENDER:
{
struct gpRender *gpr = (struct gpRender *)msg;
DrawSimpleGadget(gpr->gpr_RPort,(struct Gadget *)o,gpr->gpr_GInfo,sd,TRUE);
}
break;
case GM_HITTEST:
retval = GMR_GADGETHIT;
break;
/*** here come drag&drop related method dispatching ***/
case GM_OBJECTDRAG: // do we want the object? is some further rendering needed?
{
struct gpObjectDrag *gpod = (struct gpObjectDrag *)msg;
if ((struct Gadget *)o == gpod->gpod_Source) // get current drag position
{
ULONG current;
if (sd->sd_Direction == SDD_HORIZONTAL)
current = (gpod->gpod_Mouse.X-4+sd->sd_Range/2)/sd->sd_Range;
else
current = (gpod->gpod_Mouse.Y-4+sd->sd_Range/2)/sd->sd_Range;
retval = GMR_ACCEPTOBJECT | (current != sd->sd_CurrentDrag ? GMR_UPDATE : 0);
sd->sd_CurrentDrag = current;
}
else
{
struct Gadget *gad = gpod->gpod_Source;
if (gad && IsBoopsiGadget(gad) && OCLASS(gad) == cl) // has the source the same class then we have? (simple, no check for super-classes...)
retval = GMR_ACCEPTOBJECT; // we want it all
else
retval = GMR_REJECTOBJECT;
retval |= GMR_FINAL; // do not send this message again
}
break;
}
case GM_OBJECTDROP:
/* we do not process this method, gtdrag will send
** the DropMessage to the window's MsgPort if we
** return NULL, otherwise it will be catched by us.
*/
break;
case GM_RENDERDRAG:
{
struct gpRenderDrag *gprd = (struct gpRenderDrag *)msg;
/* GRENDER_HIGHLIGHT is the only one implemented here; let's
** gtdrag do the dirty stuff.
*/
if (gprd->gprd_Mode == GRENDER_HIGHLIGHT && sd->sd_CurrentDrag != ~0L)
{
struct RastPort *rp = gprd->gprd_RPort;
struct Gadget *gad = (APTR)o;
int current = sd->sd_CurrentDrag * sd->sd_Range;
rp->linpatcnt = 15; rp->Flags |= FRST_DOT;
rp->LinePtrn = 0x0f0f;
SetABPenDrMd(rp,1,2,JAM2); // use gprd_GInfo->gi_DrInfo->dri_Pens[] instead
if (sd->sd_Direction == SDD_HORIZONTAL)
{
Move(rp,gad->LeftEdge+current+4,gad->TopEdge+2);
Draw(rp,gad->LeftEdge+current+4,gad->TopEdge+gad->Height-3);
}
else
{
Move(rp,gad->LeftEdge+4,gad->TopEdge+3+current);
Draw(rp,gad->LeftEdge+gad->Width-4,gad->TopEdge+3+current);
}
retval = TRUE;
}
else if (gprd->gprd_Mode == GRENDER_DELETE)
sd->sd_CurrentDrag = ~0L; // reset temporary drag position
break;
}
case GM_GOACTIVE:
case GM_HANDLEINPUT:
{
struct gpInput *gpi = (struct gpInput *)msg;
struct InputEvent *ie = gpi->gpi_IEvent;
long x = gpi->gpi_Mouse.X, y = gpi->gpi_Mouse.Y;
/* test if input is for us or not */
if ((retval = GTD_HandleInput((struct Gadget *)o,gpi)) != GMR_HANDLEYOURSELF)
break;
retval = GMR_MEACTIVE;
if (ie->ie_Class == IECLASS_RAWMOUSE)
{
if (ie->ie_Code == IECODE_RBUTTON)
retval = GMR_REUSE;
else if (ie->ie_Code == (IECODE_LBUTTON | IECODE_UP_PREFIX))
{
retval = GMR_REUSE;
}
else if (ie->ie_Code == IECODE_LBUTTON)
{
struct RastPort *rp = ObtainGIRPort(gpi->gpi_GInfo);
struct Gadget *gad = (APTR)o;
if (sd->sd_Direction == SDD_HORIZONTAL)
sd->sd_Selected = (x-4)/sd->sd_Range;
else
sd->sd_Selected = (y-4)/sd->sd_Range;
DrawSimpleGadget(rp,gad,gpi->gpi_GInfo,sd,FALSE);
ReleaseGIRPort(rp);
}
else if (ie->ie_Code == IECODE_NOBUTTON && GTD_PrepareDrag((struct Gadget *)o,gpi)) // mouse movement
{
struct Gadget *gad = (struct Gadget *)o;
int i = sd->sd_Selected;
struct Node *ln;
foreach(sd->sd_List,ln) // get the current node
{
if (--i)
break;
}
GTD_SetAttrs(o,GTDA_Object, ln, // object to be dragged
GTDA_RenderHook, sd->sd_Hook, // use this to render the object
GTDA_Width, sd->sd_Direction == SDD_HORIZONTAL ? sd->sd_Range : gad->Width,
GTDA_Height, sd->sd_Direction == SDD_VERTICAL ? sd->sd_Range : gad->Height,
GTDA_Type, ODT_NODE, // it's basically a simple node
GTDA_Same, TRUE, // I want to drag&drop my objects over me
TAG_END);
GTD_BeginDrag(gad,gpi);
}
}
break;
}
case GM_GOINACTIVE:
{
struct gpInput *gpi = (struct gpInput *)msg;
struct RastPort *rp = ObtainGIRPort(gpi->gpi_GInfo);
GTD_StopDrag((struct Gadget *)o); // used to break the drag of an object, could also be used in other circumstances
sd->sd_Selected = ~0L;
DrawSimpleGadget(rp,(struct Gadget *)o,gpi->gpi_GInfo,sd,FALSE);
ReleaseGIRPort(rp);
break;
}
default:
retval = DoSuperMethodA(cl,o,msg);
}
return(retval);
}
/********************************** main programme **********************************/
void processMsg(void)
{
struct IntuiMessage *imsg;
ULONG class;
UWORD code;
BOOL ende = FALSE;
while(!ende) /* simple gtdrag message loop */
{
imsg = (struct IntuiMessage *)WaitPort(win->UserPort);
while (imsg = (struct IntuiMessage *)GTD_GetIMsg(win->UserPort))
{
class = imsg->Class;
code = imsg->Code;
switch(class)
{
case IDCMP_CLOSEWINDOW:
ende = TRUE;
break;
}
GTD_ReplyIMsg(imsg);
}
}
}
/** frees the list */
void clean(void)
{
struct Node *ln;
while(ln = RemHead(&list))
FreeMem(ln,sizeof(struct ImageNode));
}
const STRPTR text[] = {"abc","def","ghi","jkl","mno","pqr",NULL};
/** initializes the list to be used by the SimpleGadget */
void init(void)
{
struct ImageNode *in;
int i;
NewList(&list);
for(i = 0;text[i];i++)
{
if (in = AllocMem(sizeof(struct ImageNode),MEMF_CLEAR))
{
in->in_Name = text[i];
AddTail(&list,(APTR)in);
}
}
}
/** initializes all stuff is needed */
void main(void)
{
struct Screen *scr;
struct DrawInfo *dri;
void *vi;
struct Gadget *hgad,*vgad;
if (!(simplegclass = MakeClass(NULL,"gadgetclass",NULL,sizeof(struct SimpleGData),0)))
return;
simplegclass->cl_Dispatcher.h_Entry = (ULONG (*)())DispatchSimpleGadget;
if (GTDragBase = OpenLibrary("gtdrag.library",3))
{
if (GTD_AddApp("boopsitest",GTDA_NewStyle,TRUE,TAG_END))
{
if (scr = LockPubScreen(NULL))
{
fontheight = scr->Font->ta_YSize;
dri = GetScreenDrawInfo(scr);
init();
if (vi = GetVisualInfo(scr,TAG_END))
{
if (hgad = NewObject(simplegclass,NULL,GA_Left, scr->WBorLeft,
GA_Top, fontheight+scr->WBorTop+1,
GA_Width, 300-scr->WBorRight-scr->WBorLeft,
GA_Height, fontheight+9,
SDA_List, &list,
SDA_Items, 5,
SDA_Direction, SDD_HORIZONTAL,
TAG_END))
{
int y; /* fill the stack with some useless stuff */
if (vgad = NewObject(simplegclass,NULL,GA_Left, scr->WBorLeft,
GA_Top, y = 2*fontheight+scr->WBorTop+10,
GA_Width, 40,
GA_Height, 200-scr->WBorBottom-y,
GA_Previous, hgad,
SDA_List, &list,
SDA_Items, 5,
SDA_Direction, SDD_VERTICAL,
TAG_END))
{
if (win = OpenWindowTags(NULL,WA_Title, "gtdrag - Boopsi-Example",
WA_Width, 300,
WA_Height, 200,
WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE,
WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_IDCMPUPDATE | DRAGIDCMP,
WA_Gadgets, hgad,
WA_PubScreen, scr,
TAG_END))
{
processMsg();
RemoveGList(win,hgad,-1);
CloseWindow(win);
}
DisposeObject(vgad);
}
DisposeObject(hgad);
}
FreeVisualInfo(vi);
}
clean();
FreeScreenDrawInfo(scr,dri);
UnlockPubScreen(NULL,scr);
}
GTD_RemoveApp();
}
CloseLibrary(GTDragBase);
}
FreeClass(simplegclass);
}